import React from 'react';
import { UseMutationResult } from '@tanstack/react-query';
import { AxiosResponse } from 'axios';
import Table from '@components/Table/Table';
import Flex from '@components/Flex/Flex';
import Button from '@components/Button/Button';
import Snipper from '@components/Spinner/Spinner';
import {
    WindowsIcon,
    LinuxIcon,
    AndroidIcon,
    MacIcon,
    EdgeIcon,
    ChromeIcon,
    FirefoxIcon,
    YandexIcon,
} from '../../../images/index';
import ContainerCard from '../../ContainerCard/ContainerCard';
import { StyledLabelCard } from '../LabelCard.styled';
import { ISession } from '../../../types/sessionType';
import { HeaderColumnType } from '../../../shared/ui/Table/Table.types';
import { IDisplayedSessionData } from './SessionCard.types';
import { createDate, formatDate } from '../../../utils/date';
import { useConfirmationModal } from '../../../components/ConfirmationModalProvider/ConfirmationModalProvider';
import { useSessionCRUD } from './useSessionCRUD';
import buttonStyles from '../ButtonStyle.module.scss';
import styles from './SessionCard.module.scss';

/**
 * Массив заголовков для таблицы сессий.
 * @type { HeaderColumnType[] }
 */
const headerArray: HeaderColumnType[] = [
    {
        title: 'ОС',
        name: 'os',
    },
    {
        title: 'Браузер',
        name: 'browser',
    },
    {
        title: 'IP',
        name: 'ip',
    },
    {
        title: 'Регион',
        name: 'region',
    },
    {
        title: 'Город',
        name: 'city',
    },
    {
        title: 'Дата последнего сеанса',
        name: 'created_date',
    },
    {
        title: 'Дата последнего изменения',
        name: 'changed_date',
    },
    {
        title: '',
        name: 'actions',
    },
];

/**
 * Генерирует значок ОС на основе данного типа ОС.
 *
 * @param { string } osType - Тип операционной системы.
 * @return { React.ReactElement } - Элемент значка ОС, или null, если тип ОС не распознан.
 */
const selectOsIcon = (osType: string): React.ReactElement => {
    const OS: Record<string, React.ReactElement> = {
        Windows: <WindowsIcon />,
        Linux: <LinuxIcon />,
        Android: <AndroidIcon />,
        'Mac OS': <MacIcon />,
    };

    return OS[osType] || null;
};

/**
 * Возвращает соответствующую иконку браузера на основе указанного типа браузера.
 *
 * @param { string } browserType - Тип браузера.
 * @return { React.ReactElement } - Соответствующая иконка браузера.
 */
const selectBrowserIcon = (browserType: string): React.ReactElement => {
    const browser: Record<string, React.ReactElement> = {
        Edge: <EdgeIcon />,
        Chrome: <ChromeIcon />,
        Firefox: <FirefoxIcon />,
        Yandex: <YandexIcon />,
    };

    return browser[browserType] || null;
};

/**
 * @typedef { Object } - Тип возврата функции getopenOptions 
 */
type OpenOptions = {
    content: string,
    actions: React.ReactNode
};

/**
 * @function getOpenOptions - Создает объект с параметрами для модального окна,
 * основываясь на том, относится ли оно к текущему
 * сеансу, предлагая сообщение и соответствующие действия.
 *
 * @param { boolean } isCurrentSession - Флаг, указывающий,
 *        является ли сеанс текущим.
 * @param { string } sid - Идентификатор сеанса.
 * @param { UseMutationResult<AxiosResponse<any, any>, Error,
*        string, unknown> } deleteSession - Результат мутации
*        для удаления сеанса.
* @param { () => void } close - Функция для закрытия модального
*        окна.
* @return { OpenOptions } - Объект с содержимым и действиями
*         для модального окна.
*/
function getOpenOptions(
    isCurrentSession: boolean,
    sid: string,
    deleteSession: UseMutationResult<AxiosResponse<any, any>, Error, string, unknown>,
    close: () => void,
): OpenOptions {
    const baseOptions = {
        content: isCurrentSession
            ? 'Этот сеанс является текущим'
            : 'Вы действительно хотите удалить сеанс?',
        actions: (
            <Flex justifyContent={isCurrentSession ? 'center' : 'space-around'}>
                <Button onClick={close}>Отмена</Button>
                {!isCurrentSession && (
                    <Button
                        onClick={() => {
                            deleteSession.mutateAsync(sid).then(close);
                        }}
                    >
                        Удалить
                    </Button>
                )}
            </Flex>
        ),
    };
    return baseOptions;
}

/**
 * @function SessionCard - Отрисовывает компонент SessionsCard.
 * @return {React.ReactElement} - Компонент SessionCard.
 */
const SessionsCard: React.FC = (): React.ReactElement => {
    const { open, close } = useConfirmationModal();

    const { data, isLoading, deleteSession } = useSessionCRUD();

    /**
     * @function handlerModal - Обрабатывает событие модального окна.
     * @param {React.MouseEvent<HTMLButtonElement, MouseEvent>} event - Событие мыши.
     * @param {ISession} el - Элемент сессии.
     */
    const handlerModal = (
        event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
        el: ISession,
    ) => {
        event.stopPropagation();

        if (!el.current) {
            open(getOpenOptions(false, el.sid, deleteSession, close));
        } else {
            open(getOpenOptions(true, el.sid, deleteSession, close));
        }
    }

    /**
     * @function getDisplayedSessionData - Генерирует массив отображаемых в таблице данных
     *  на основе предоставленных данных сеанса.
     * @return { IDisplayedSessionData[]} - Массив отображаемых данных сеанса.
     */
    const getDisplayedSessionData = React.useMemo(
        () => (): IDisplayedSessionData[] => {
            const newDisplayedSessionData: IDisplayedSessionData[] = data.map(
                (el, index) => ({
                    id: index,
                    disabled: false,
                    os: (
                        <Flex>
                            <div className={styles.iconStyle}>
                                {selectOsIcon(el.user_agent.os.name)}
                            </div>
                            &nbsp;
                            {el.user_agent.os.name}
                        </Flex>
                    ),
                    browser: (
                        <Flex>
                            <div className={styles.iconStyle}>
                                {selectBrowserIcon(el.user_agent.browser.name)}
                            </div>
                            &nbsp;
                            {el.user_agent.browser.name}
                        </Flex>
                    ),
                    ip: el.location.ip,
                    region: el.location.region,
                    city: el.location.city,
                    created_date:
                        formatDate(createDate(el.created_date)) ?? 'неизвестно',
                    changed_date:
                        formatDate(createDate(el.changed_date)) ?? 'неизвестно',
                    actions: (
                        <Button
                            className={buttonStyles.buttonStyle}
                            onClick={event => handlerModal(event, el)}
                        >
                            Удалить
                        </Button>
                    ),
                    current: el.current,
                }),
            );

            return newDisplayedSessionData;
        },
        [data],
    );

    return (
        <div className={styles.sessionCard} id="sessionsCard">
            <StyledLabelCard>Подсоединенные устройства</StyledLabelCard>
            <ContainerCard>
                {isLoading ? (
                    <Snipper />
                ) : (
                    <Table
                        rowList={getDisplayedSessionData()}
                        columnList={headerArray}
                        selectedRows={[
                            getDisplayedSessionData()?.find(el => el.current)
                                ?.id,
                        ]}
                        enableActions
                        striped
                    />
                )}
            </ContainerCard>
        </div>
    );
};

export default SessionsCard;
